#pragma once

#include "../Algorithm/algorithm.h"

using namespace System;
using namespace System::Drawing;
using namespace System::Collections;

namespace StereoCorrespond {
/*	ref class Filter {
		ref struct Index : IComparable {
			float X;
			float Y;

			Index(float x, float y) :
				X(x),
				Y(y)
			{ }

			virtual float32 CompareTo(Object^ other) {
				if(!other)
					throw gcnew Exception("Null pofloater!");
				Index^ index = dynamic_cast<Index^>(other);
				if(!index)
					throw gcnew Exception("Wrong type!");
				if(X < index->X)
					return -1;
				else if(X == index->X)
					return Y.CompareTo(index->Y);
				else
					return 1;
			}
		};

		Collections::Generic::SortedDictionary<Index^, double> Items;
		double sumWeight;

		float _minx;
		float _maxx;
		float _miny;
		float _maxy;

		bool _separated;

	public:
		property float MinX {
			float get() { return _minx; }
		}

		property float MaxX {
			float get() { return _maxx; }
		}

		property float MinY {
			float get() { return _miny; }
		}

		property float MaxY {
			float get() { return _maxy; }
		}

		property bool Separated {
			bool get() { return _separated; }
		}

		double calculatePixel(Bitmap^ src, Pofloat pixel)
		{
			double sum = 0.0f;
			float max_width = src->Width-1;
			float max_height = src->Height-1;
			for each(Index^ index in Items.Keys) {
				float x = pixel.X + index->X;
				float y = pixel.Y + index->Y;

				// clamp
				x = Math::Max(Math::Min(max_width, x), 0);
				y = Math::Max(Math::Min(max_height, y), 0);
				
				sum += Items[index]*(src->GetPixel(x, y).R/255.0f);	// we use just the R channel
			}
			return sum/sumWeight;
		}

		double calculatePixelSeparated(Bitmap^ src, Pofloat pixel)
		{
			double sum = 0.0f;
			float max_width = src->Width-1;
			for each(Index^ index in Items.Keys) {
				float x = pixel.X + index->X;

				// clamp
				x = Math::Max(Math::Min(max_width, x), 0);
				
				sum += Items[index]*(src->GetPixel(x, pixel.Y).R/255.0f);	// we use just the R channel
			}
			return sum/sumWeight;
		}

		double calculatePixelSeparatedTransponse(Bitmap^ src, Pofloat pixel)
		{
			double sum = 0.0f;
			float max_height = src->Height-1;
			for each(Index^ index in Items.Keys) {
				float y = pixel.Y + index->X;

				// clamp
				y = Math::Max(Math::Min(max_height, y), 0);
				
				sum += Items[index]*(src->GetPixel(pixel.X, y).R/255.0f);	// we use just the R channel
			}
			return sum/sumWeight;
		}

		virtual String^ ToString() override {
			String^ ret = String::Empty;
			for each(Index^ index in Items.Keys) {
				ret += "(" + index->X + ", " + index->Y + ") : " + Items[index] + "\n";
			}
			ret += "sum: " + sumWeight + "\n";
			ret += "sep: " + _separated;
			return ret;
		}

		Bitmap^ Run(Bitmap^ src) {
			Bitmap^ ret = gcnew Bitmap(src->Width, src->Height);
			if(!_separated) {
				for(float i=0; i<src->Width; ++i) {
					for(float j=0; j<src->Height; ++j) {
						float floatensity = (float)(calculatePixel(src, Pofloat(i,j))*255.0f);
						ret->SetPixel(i, j, Color::FromArgb(floatensity, floatensity, floatensity));
					}
				}
			}
			else {
				Bitmap^ dst = gcnew Bitmap(src->Width, src->Height);
				for(float i=0; i<dst->Width; ++i) {
					for(float j=0; j<dst->Height; ++j) {
						float floatensity = (float)(calculatePixelSeparated(src, Pofloat(i,j))*255.0f);
						dst->SetPixel(i, j, Color::FromArgb(floatensity, floatensity, floatensity));
					}
				}
				for(float i=0; i<ret->Width; ++i) {
					for(float j=0; j<ret->Height; ++j) {
						float floatensity = (float)(calculatePixelSeparatedTransponse(dst, Pofloat(i,j))*255.0f);
						ret->SetPixel(i, j, Color::FromArgb(floatensity, floatensity, floatensity));
					}
				}
			}
			return ret;
		}

		static Filter^ createGauss(double sigma) {
		//	Not separated
		//	Filter^ ret = gcnew Filter();
		//	double sqrSigma_2 = 2.0*System::Math::Pow(sigma, 2.0);
		//	double maxr = 2.5f*sigma;
		//	ret->_minx = ret->_miny = -(float)maxr;
		//	ret->_maxx = ret->_maxy = (float)maxr;
		//	ret->sumWeight = 0.0;
		//	for(float i=ret->_minx; i<=ret->_maxx; ++i) {
		//		for(float j=ret->_miny; j<=ret->_maxy; ++j) {
		//			double sqrR = (double)(i*i + j*j);
		//			double r = System::Math::Sqrt(sqrR);
		//			if(r <= maxr)
		//			{
		//				double weight = System::Math::Exp(-sqrR/sqrSigma_2)/sqrSigma_2; // No need for /PI
		//				ret->Items.Add(gcnew Index(i, j), weight);
		//				ret->sumWeight += weight;
		//			}
		//		}
		//	}
		//	return ret;
		
			Filter^ ret = gcnew Filter();
			ret->_separated = true;
			double sqrSigma_2 = 2.0*System::Math::Pow(sigma, 2.0);
			double maxr = 2.5f*sigma;
			ret->_miny = ret->_maxy = 0;
			ret->_minx = -(float)maxr;
			ret->_maxx = (float)maxr;
			ret->sumWeight = 0.0;
			for(float i=ret->_minx; i<=ret->_maxx; ++i) {
				double sqrR = (double)(i*i);
				double r = i;
				if(r <= maxr)
				{
					double weight = System::Math::Exp(-sqrR/sqrSigma_2)/sqrSigma_2; // No need for /PI
					ret->Items.Add(gcnew Index(i, 0), weight);
					ret->sumWeight += weight;
				}
			}
			return ret;
		}
	};*/
	
	Bitmap^ toCLRBitmap(Algorithm::Bitmap<float>* bitmap);
	Bitmap^ toCLRBitmap(Algorithm::Bitmap<float2>* bitmap);
	Bitmap^ toCLRBitmap(Algorithm::Bitmap<float3>* bitmap);
	Bitmap^ toCLRBitmap(Algorithm::Bitmap<float4>* bitmap);
	
	Algorithm::Bitmap<float>* toBitmap_float(Bitmap^ bitmap);
	Algorithm::Bitmap<float2>* toBitmap_float2(Bitmap^ bitmap);
	Algorithm::Bitmap<float3>* toBitmap_float3(Bitmap^ bitmap);
	Algorithm::Bitmap<float4>* toBitmap_float4(Bitmap^ bitmap);
	
	Bitmap^ toCLRBitmap(Algorithm::Bitmap<int>* bitmap);
	Bitmap^ toCLRBitmap(Algorithm::Bitmap<int2>* bitmap);
	Bitmap^ toCLRBitmap(Algorithm::Bitmap<int3>* bitmap);
	Bitmap^ toCLRBitmap(Algorithm::Bitmap<int4>* bitmap);
	
	Algorithm::Bitmap<int>* toBitmap_int(Bitmap^ bitmap);
	Algorithm::Bitmap<int2>* toBitmap_int2(Bitmap^ bitmap);
	Algorithm::Bitmap<int3>* toBitmap_int3(Bitmap^ bitmap);
	Algorithm::Bitmap<int4>* toBitmap_int4(Bitmap^ bitmap);

	//Image^ Harris(Bitmap^ src, double gaussSigma);
}